package org.smarthings.things.automation.scripting.engine;

import java.util.List;

import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.osgi.service.component.ComponentContext;
import org.smarthings.things.automation.engine.ThingsRegistryFacade;

public class ScriptingEngineFacade {

	private ScriptEngineManager scriptEngineManager;
	private ThingsRegistryFacade thingsRegistryFacade;

	public ScriptingEngineFacade(ScriptEngineManager scriptEngineManager) {
		this.scriptEngineManager = scriptEngineManager;
	}

	public void activate(ThingsRegistryFacade thingsRegistryFacade) throws IllegalStateException {
		this.thingsRegistryFacade = thingsRegistryFacade;
		List<ScriptEngineFactory> factories = this.scriptEngineManager.getEngineFactories();
		if (factories == null || factories.size() == 0) {
			throw new IllegalStateException("No scripting engines available!");
		}
		
//		List<ScriptEngineFactory> engines = scriptEngineManager.getEngineFactories();
//		if (engines.isEmpty()) {
//			System.out.println("No scripting engines were found");
//			return;
//		}
//
//		System.out.println("The following " + engines.size() + " scripting engines were found");
//		System.out.println();
//		for (ScriptEngineFactory engine : engines) {
//			try {
//				System.out.println("Engine name: " + engine.getEngineName());
//				System.out.println("\tVersion: " + engine.getEngineVersion());
//				System.out.println("\tLanguage: " + engine.getLanguageName());
//				List<String> extensions = engine.getExtensions();
//				if (extensions.size() > 0) {
//					System.out.println("\tEngine supports the following extensions:");
//					for (String e : extensions) {
//						System.out.println("\t\t" + e);
//					}
//				}
//				List<String> shortNames = engine.getNames();
//				if (shortNames.size() > 0) {
//					System.out.println("\tEngine has the following short names:");
//					for (String n : engine.getNames()) {
//						System.out.println("\t\t" + n);
//					}
//				}
//			} catch (Throwable e) {
//				System.out.println("ERROR whil listing script engine information: "
//						+ e.getMessage());
//				e.printStackTrace();
//			}
//			System.out.println("=========================");
//		}
	}

	public void deactivate(ComponentContext context) {
		this.scriptEngineManager = null;
	}

	public Object evaluate(String language, String script, ScriptingContext context)
			throws ScriptException, IllegalArgumentException {

		ScriptEngine engine = scriptEngineManager.getEngineByName(language);
		if (engine == null) {
			throw new IllegalArgumentException("No scripting engine found for script language "
					+ language);
		}

		Bindings bindings = engine.createBindings();
		bindings.put("rule", context.getRule());
		bindings.put("events", context.getEvents());
		bindings.put("things", thingsRegistryFacade);
		bindings.put("out", System.out); // FIXME remove, for testing only!
		bindings.putAll(context.getBindings());
		return engine.eval(script, bindings);
	}

	public boolean supports(String language) {
		List<ScriptEngineFactory> factories = scriptEngineManager.getEngineFactories();
		if (factories != null && factories.size() > 0) {
			for (ScriptEngineFactory factory : factories) {
				if (factory.getNames().contains(language)) {
					return true;
				}
			}
		}
		return false;
	}

}
